#include "stdafx.h"
#include "SystemInformation.h"

using namespace Hiranipra;
using namespace Hiranipra::HCM;
using namespace Hiranipra::Platform;

SystemInformation::SystemInformation()
{
	this->Update();
}

SystemInformation::~SystemInformation()
{
}

typedef BOOL (WINAPI *LPFN_GLPI)(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD);

bool SystemInformation::Update()
{
	_packageProcessorCount = 1;
	_physicalProcessorCount = 1;
	_logicalProcessorCount = 1;
	_averageProcessorSpeed = 2.0f;

	// Get CPU speed
	{
		HKEY hKey;
		long result = RegOpenKeyEx( HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0, KEY_READ, &hKey );
		if( result == ERROR_SUCCESS )
		{
			DWORD dwMHz = 0;
			DWORD bufferSize = sizeof( DWORD );
			RegQueryValueEx( hKey, L"~MHz", NULL, NULL, ( LPBYTE )&dwMHz, &bufferSize );
			RegCloseKey( hKey );
			_averageProcessorSpeed = dwMHz / 1000.0f;
		}
	}

	// Get processor counts
	bool hasProcessorCounts = false;
	LPFN_GLPI glpi = ( LPFN_GLPI )GetProcAddress( GetModuleHandle( L"kernel32" ), "GetLogicalProcessorInformation" );
    if( glpi != NULL )
	{
		SYSTEM_LOGICAL_PROCESSOR_INFORMATION procInfos[ 32 ];
		uint32 procInfoSize = sizeof( procInfos );
		if( GetLogicalProcessorInformation( procInfos, ( PDWORD )&procInfoSize ) == TRUE )
		{
			hasProcessorCounts = true;
			_packageProcessorCount = 0;
			_physicalProcessorCount = 0;
			_logicalProcessorCount = 0;
			int processorCount = procInfoSize / sizeof( SYSTEM_LOGICAL_PROCESSOR_INFORMATION );
			for( int n = 0; n < processorCount; n++ )
			{
				SYSTEM_LOGICAL_PROCESSOR_INFORMATION* procInfo = &procInfos[ n ];
				switch( procInfo->Relationship )
				{
					case RelationProcessorPackage:
						_packageProcessorCount++;
						break;
					case RelationProcessorCore:
						_physicalProcessorCount++;
						_logicalProcessorCount += CountSetBits( ( uint64 )procInfo->ProcessorMask );
						break;
				}
			}
		}
	}

	if( hasProcessorCounts == false )
	{
		// Fallback path for processor info
		SYSTEM_INFO systemInfo;
		GetSystemInfo( &systemInfo );
		_packageProcessorCount = 1;
		_physicalProcessorCount = _logicalProcessorCount = systemInfo.dwNumberOfProcessors;
	}

	return true;
}
